// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == 'object' && typeof module == 'object')
    mod(require('../../lib/codemirror'));
  else if (typeof define == 'function' && define.amd)
    define(['../../lib/codemirror'], mod);
  else mod(CodeMirror);
})(function(CodeMirror) {
  'use strict';

  CodeMirror.defineMode('cmake', function() {
    var variable_regex = /({)?[a-zA-Z0-9_]+(})?/;

    function tokenString(stream, state) {
      var current,
        prev,
        found_var = false;
      while (!stream.eol() && (current = stream.next()) != state.pending) {
        if (current === '$' && prev != '\\' && state.pending == '"') {
          found_var = true;
          break;
        }
        prev = current;
      }
      if (found_var) {
        stream.backUp(1);
      }
      if (current == state.pending) {
        state.continueString = false;
      } else {
        state.continueString = true;
      }
      return 'string';
    }

    function tokenize(stream, state) {
      var ch = stream.next();

      // Have we found a variable?
      if (ch === '$') {
        if (stream.match(variable_regex)) {
          return 'variable-2';
        }
        return 'variable';
      }
      // Should we still be looking for the end of a string?
      if (state.continueString) {
        // If so, go through the loop again
        stream.backUp(1);
        return tokenString(stream, state);
      }
      // Do we just have a function on our hands?
      // In 'cmake_minimum_required (VERSION 2.8.8)', 'cmake_minimum_required' is matched
      if (stream.match(/(\s+)?\w+\(/) || stream.match(/(\s+)?\w+\ \(/)) {
        stream.backUp(1);
        return 'def';
      }
      if (ch == '#') {
        stream.skipToEnd();
        return 'comment';
      }
      // Have we found a string?
      if (ch == "'" || ch == '"') {
        // Store the type (single or double)
        state.pending = ch;
        // Perform the looping function to find the end
        return tokenString(stream, state);
      }
      if (ch == '(' || ch == ')') {
        return 'bracket';
      }
      if (ch.match(/[0-9]/)) {
        return 'number';
      }
      stream.eatWhile(/[\w-]/);
      return null;
    }
    return {
      startState: function() {
        var state = {};
        state.inDefinition = false;
        state.inInclude = false;
        state.continueString = false;
        state.pending = false;
        return state;
      },
      token: function(stream, state) {
        if (stream.eatSpace()) return null;
        return tokenize(stream, state);
      },
    };
  });

  CodeMirror.defineMIME('text/x-cmake', 'cmake');
});
